from django.db import transaction
from django.shortcuts import render
from rest_framework import status, serializers
from rest_framework.decorators import action
from rest_framework.mixins import ListModelMixin, CreateModelMixin
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
from urllib3 import request
from  celery_tasks.email.tasks import  send_mail_task

from jt31.settings import alipay
from shopping.models import Classification, Commodity, CommodityImg, ShoppingCart, Order, Payment
from shopping.serialzers import ClassificationsSerializer, ParentClassificationsSerializer, CommoditySerializer, \
    ShoppingCartSerializer, OrderSerializer, PaymentSerializer
import logging
from fdfs_client.client import Fdfs_client,get_tracker_conf
# 创建日志对象
logger = logging.getLogger('__name__')
# 创建fastdfs客户端对象
tracker_path =  get_tracker_conf("fastdfs/client.conf")

# 通过配置文件地址  创建fafsdfs的客户端
client = Fdfs_client(tracker_path)
# Create your views here.

# 分类的视图
# 只需要 查看的功能
class ClassificationViewSet(GenericViewSet,ListModelMixin):
    queryset = Classification.objects.filter(is_delete=False)
    serializer_class = ClassificationsSerializer
    # 登录权限
    permission_classes = [IsAuthenticated]


    # 查询集
    # 查看所有的分类的时候  只展示一级分类   list
    def get_queryset(self):
        if self.action == 'list':
            # 没有被逻辑删除的  并且  没有父级 parent
            return self.queryset.filter(parent__isnull=True)
        else:
            return self.queryset

    # 序列化器
    def get_serializer_class(self):
        if self.action == 'list':
            return ParentClassificationsSerializer
        else:
            return self.serializer_class


    # 根据分类展示所有的商品
    @action(methods=['get'],detail=True)
    def commodity(self,request,pk):# 2
        # 根据传入的id获取指定的分类数据
        try:
            classification_res = self.get_queryset().get(id = pk)
        except Classification.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # 乐观的假设 不管传入的id 是多少  我们都认为是一级分类
        classification_attr = "classification1"
        classification_name = classification_res.name
        # 改分类是一级分类还是二级分类
        if classification_res.parent:# 判断有没有parent
            # 二级分类
            classification_attr = "classification2"
            classification_name = f"{classification_res.parent.name}---{classification_res.name}"
        # classification_res.classification_attr
        # 怎么得到分类对应的商品数据呢
        data = getattr(classification_res, classification_attr)
        # 商品数据
        commmqueryset = data.filter(is_delete=False,status=1)
        return  Response({
            "classification":classification_name,
            "commodity":CommoditySerializer(commmqueryset,many=True).data,
        })

# 商品的视图
class CommodityViewSet(ModelViewSet):
    queryset = Commodity.objects.filter(is_delete=False)
    serializer_class = CommoditySerializer
    permission_classes = [IsAuthenticated]


    # 查询接口
    # 必须是发布的商品
    def get_queryset(self):
        if self.action in ['list','retrieve']:
            return self.queryset.filter(status=1)
        else:
            return self.queryset


    # 添加商品
    # 添加图片
    # 重写 create 方法
    def create(self, request, *args, **kwargs):
        # 得到客户端传入的数据 进行反序列化
        serialzier = self.get_serializer(data = request.data)
        # 数据校验
        serialzier.is_valid(raise_exception=True)
        # 保存商品
        serialzier.save()

        # 商品图片的获取
        files = request.FILES.getlist("file")
        # 多个图片
        for file in files:
            if file:
                # 判断是否是图片
                if file.content_type not in ['image/png', 'image/jpeg']:
                    return Response(status=status.HTTP_400_BAD_REQUEST)
                try:
                    # 如果没有文件后缀 1.png
                    image_ext_name = file.name.split('.')[-1]  # ["1" , "png"]
                except Exception as e:
                    logger.info(f"图片的扩展名异常{e}")
                    image_ext_name = "png"
                # 进行持久化存储  storage（存储服务端）
                try:
                    # upload_by_filename  ==> upload_by_buffer
                    # 数据 和文件的后缀  ===》 storage  ===》xxxxxx.png
                    uploade_res = client.upload_by_buffer(file.read(), file_ext_name=image_ext_name)
                except Exception as e:
                    logger.error(f"图片上传出现异常{e}")
                    return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                else:
                    # 再进行数据库的持久化存储  图片地址
                    if uploade_res.get("Status") != "Upload successed.":
                        logger.warning("图片上传失败")
                        return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                    else:
                        # 字节文件  ===》 字符文件
                        image_url = uploade_res.get("Remote file_id").decode()

                        # 存入到图片数据库中
                        CommodityImg.objects.create(src =image_url,commodity_id=serialzier.data['id'])

        return Response(serialzier.data)


    # 商场优选数据展示
    @action(methods=['get'],detail=False)
    def optimization(self,request):

        queryres = self.get_queryset().order_by('-sales').order_by('-comments').order_by('-created_time')

        if len(queryres) >=5:
            queryres = queryres[:5]

        # 查询集 多条数据
        serializer = self.get_serializer(queryres,many=True)
        return Response(serializer.data)



# 购物车视图
class ShoppingCartViewSet(ModelViewSet):
    queryset = ShoppingCart.objects.all()
    serializer_class = ShoppingCartSerializer
    # 登录权限
    permission_classes = [IsAuthenticated]

    # 对于购物车 只有该用户才能查看该用户的购物车
    def get_queryset(self):
        # 用户模型.购物车
        return self.request.user.shoppingcart_set.all()

    # 用户添加商品进入购物车
    def create(self, request, *args, **kwargs):
        request.POST._mutable = True
        request.data["user"] = request.user.id

        return ModelViewSet.create(self, request, *args, **kwargs)


# 订单   创建订单    用户只能读取订单
class OrderViewSet(ReadOnlyModelViewSet,CreateModelMixin):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    permission_classes = [IsAuthenticated]

    # 只有该用户才能查看该用户的订单
    def get_queryset(self):
        # 获取对应用户的所有订单
        return self.request.user.order_set.all()

    @action(methods=['put'],detail=False)
    def status(self,request):
        # 修改订单状态
        # 支付宝会回调一个 支付交易号
        # 订单编号
        data = request.query_params.dict()
        # 获取交易号
        trade_no = data["trade_no"]
        # 获取订单编号
        order_id = data["out_trade_no"]

        # 事务
        with transaction.atomic():
            # 保存点
            save_point = transaction.savepoint()
            try:

                # 存入到 Payment
                Payment.objects.create(order_id=order_id,trade_id=trade_no)
                # 修改订单状态
                self.get_queryset().filter(order_id=order_id,status=1).update(status=2)
            except Exception as e:
                transaction.rollback()
                raise serializers.ValidationError(e)
            else:
                transaction.savepoint_commit(save_point)
                # 发送邮件
                # 获取订单所有的商品详情信息
                ordergoodslist = self.get_queryset().get(order_id=order_id).ordergoods_set.all() # 订单详情表的查询集
                for i in ordergoodslist:
                    # delay 异步发送方法  i 订单详情的模型对象.order.user
                    send_mail_task.delay(i.order.user.email,f"""
                    <h1>恭喜您下单成功</h1>,
                    <h4>您在咱们jutong31系统购买的【{i.commodity.name}】 【{i.number}】</h4>
                     <h1>欢迎您下次光临</h1>,
                    """)

        return Response({'order_id':order_id,"trade_id":trade_no})




# # 只需要读取  和创建
class PaymentViewSet(ReadOnlyModelViewSet):
    queryset = Payment.objects.all()
    serializer_class = PaymentSerializer
    permission_classes = [IsAuthenticated]

    @action(methods=['get'],detail=True)
    def pay(self,request,pk):
        # 针对当前登录的用户订单 并且没有支付
        try:
            #获取订单数据
            order = Order.objects.get(order_id=pk,user = request.user,status = 1)
        except Order.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        # 支付宝对象
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no= order.order_id, # 订单号
            total_amount = str(order.total_amount), # 总金额
            subject = f"Jutong31系统{order.order_id}", # 支付标题
            # 成功支付之后的跳转页面
            return_url= "http:127.0.0.1:8080/order/success"
        )

        # 拿到支付宝的测试接口
        pay_url = "https://openapi-sandbox.dl.alipaydev.com/gateway.do?"+order_string

        return Response({"pay_url":pay_url})


"""
celery: 异步任务队列
同步： 发送请求  ===》 服务器（返回相应，未返回相应的时候，不会继续下一步）==》下一步
异步:  发送请求 ===》 服务器 （未返回相应）> 继续下一步 

# 队列  先进先出   栈 先进后出
#
任务队列   redis
客户端 django
服务端  celerey

"""

